from __future__ import absolute_import, division, print_function, unicode_literals

import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])

# Import the backtrader platform
import backtrader as bt

import MySQLDataFeed as mdf
import SimpleMySqlClass as smc


class DoubleAverages(bt.Strategy):

    params = (("period_sma20", 20), ("period_sma60", 60))

    # 打印日志
    def log(self, txt, dt=None):

        dt = dt or self.data.datetime.date(0)
        print("%s, %s" % (dt, txt))

    def __init__(self):

        # 用于保存订单
        self.order = None
        # 订单价格
        self.buyprice = None
        # 订单佣金
        self.buycomm = None

        # 定义变量保存所有收盘价
        self.dataopen = self.data.open
        self.datahigh = self.data.high
        self.datalow = self.data.low
        self.dataclose = self.data.close

        # 计算20日均线
        self.sma20 = bt.indicators.MovingAverageSimple(
            self.dataclose, period=self.params.period_sma20
        )
        # 计算60日均线
        self.sma60 = bt.indicators.MovingAverageSimple(
            self.dataclose, period=self.params.period_sma60
        )
        # self.sma = bt.talib.T3(self.data, timeperiod=self.params.period_sma20)

        # Indicators for the plotting show
        bt.indicators.ExponentialMovingAverage(self.datas[0], period=25)
        # bt.indicators.WeightedMovingAverage(self.datas[0], period=25, subplot=True)
        # bt.indicators.StochasticSlow(self.datas[0])
        bt.indicators.MACDHisto(self.datas[0])
        rsi = bt.indicators.RSI(self.datas[0])
        bt.indicators.SmoothedMovingAverage(rsi, period=10)
        bt.indicators.ATR(self.datas[0], plot=False)

    def notify_order(self, order):

        # 等待订单提交、订单被cerebro接受
        if order.status in [order.Submitted, order.Accepted]:
            return

        # 等待订单完成
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(
                    "买 EXECUTED, 开仓价格: %.2f, 花费: %.2f, Comm %.2f"
                    % (order.executed.price, order.executed.value, order.executed.comm)
                )

            else:
                self.log(
                    "卖 EXECUTED, 卖出价格: %.2f, 收回资金: %.2f, Comm %.2f"
                    % (order.executed.price, order.executed.value, order.executed.comm)
                )

        # 如果订单保证金不足，将不会完成，而是执行以下拒绝程序
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log("拒绝执行，Order Canceled/Margin/Rejected")

        self.order = None

    def notify_trade(self, trade):

        if not trade.isclosed:
            return

        self.log(
            "开始交易 PROFIT, GROSS %.2f, NET %.2f" % (trade.pnl, trade.pnlcomm)
        )  # pnl：盈利  pnlcomm：手续费

    # 策略逻辑实现
    def next(self):
        # print("open = ", self.dataopen[0])
        # BOP = bt.talib.BOP(
        #     self.data.lines.open[0],
        #     self.data.lines.high[0],
        #     self.data.lines.low[0],
        #     self.data.lines.close[0],
        # )
        # print("bop -", BOP)
        # print("bop = ", self.data)
        # print("bop0 = ", self.data[0])
        # print("bop1 = ", self.d
        # ata[1])
        # print("bop2 = ", self.data[2])
        # print("bop3 = ", self.data[3])
        # print("self.data.lines.dir", dir(self.data.lines))
        # print("open = ", self.data.lines.open[0])
        # print("high = ", self.data.lines.high[0])
        # print("low = ", self.data.lines.low[0])
        # print("close = ", self.data.lines.close[0])

        # 当今天的20日均线大于60日均线并且昨天的20日均线小于60日均线，则进入市场（买）
        if self.sma20[0] > self.sma60[0] and self.sma20[-1] < self.sma60[-1]:
            # 判断订单是否完成，完成则为None，否则为订单信息
            if self.order:
                return

            # 若上一个订单处理完成，可继续执行买入操作
            self.order = self.buy()

        # 当今天的20日均线小于60日均线并且昨天的20日均线大于60日均线，则退出市场（卖）
        elif self.sma20[0] < self.sma60[0] and self.sma20[-1] > self.sma60[-1]:
            # 卖出
            self.order = self.sell()


if __name__ == "__main__":
    print("SMA:", bt.talib.MA_Type.SMA)
    print("T3:", bt.talib.MA_Type.T3)

    # Create a cerebro entity
    cerebro = bt.Cerebro()

    # Add a strategy
    cerebro.addstrategy(DoubleAverages)

    tableName = "t_stock_k_data"
    sql = f"select sd_date, sd_open, sd_high, sd_low, sd_close, sd_volume from {tableName}"
    # sql = f"select sd_date as date, sd_code as code, sd_open as code, sd_high as high, sd_low as low, sd_close as low, sd_volume as volume, sd_amount as amount from {tableName}"

    data = mdf.MySQLDataFeed(sql)

    # Add the Data Feed to Cerebro
    cerebro.adddata(data, name="2Line")

    # Set our desired cash start
    cerebro.broker.setcash(1000.0)

    # Add a FixedSize sizer according to the stake
    cerebro.addsizer(bt.sizers.FixedSize, stake=10)

    # Set the commission
    cerebro.broker.setcommission(commission=0.0005)

    # Print out the starting conditions
    print("Starting Portfolio Value: %.2f" % cerebro.broker.getvalue())

    # Run over everything
    cerebro.run()

    # Print out the final result
    print("Final Portfolio Value: %.2f" % cerebro.broker.getvalue())

    # Plot the result
    cerebro.plot(style="candle", barup="red", bardown="green")
